{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Game of Life\n",
    "\n",
    "Code examples from [Think Complexity, 2nd edition](http://greenteapress.com/wp/complexity2), Chapter 6\n",
    "\n",
    "Copyright 2016 Allen Downey, [MIT License](http://opensource.org/licenses/MIT)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For the animations in this notebook to work, you might have to install\n",
    "ffmpeg.  On Ubuntu and Linux Mint, the following should do it:\n",
    "\n",
    "    sudo add-apt-repository ppa:mc3man/trusty-media\n",
    "    sudo apt-get update\n",
    "    sudo apt-get install ffmpeg\n",
    "    \n",
    "If you have instructions for other operating systems, please let me know and I will add them here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function, division\n",
    "\n",
    "%matplotlib inline\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import thinkplot\n",
    "\n",
    "from matplotlib import rc\n",
    "rc('animation', html='html5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from thinkstats2 import RandomSeed\n",
    "RandomSeed(17)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Game of Life entities"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from Life import Life, LifeViewer\n",
    "\n",
    "def make_viewer(n, m, row, col, *strings):\n",
    "    \"\"\"Makes a Life and LifeViewer object.\n",
    "    \n",
    "    n, m: rows and columns of the Life array\n",
    "    row, col: upper left coordinate of the cells to be added\n",
    "    strings: list of strings of '0' and '1'\n",
    "    \"\"\"\n",
    "    life = Life(n, m)\n",
    "    life.add_cells(row, col, *strings)\n",
    "    viewer = LifeViewer(life)\n",
    "    return viewer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A beehive is a stable entity, also called a \"still life\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# beehive\n",
    "viewer = make_viewer(3, 4, 0, 0, '0110', '1001', '0110')\n",
    "viewer.draw(grid=True)\n",
    "plt.savefig('chap06-1.pdf')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's what it looks like after one step:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "viewer.step()\n",
    "viewer.draw(grid=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A toad is an oscillator with period 2.  Here's are its two configurations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# toad\n",
    "thinkplot.preplot(cols=2)\n",
    "viewer = make_viewer(4, 4, 1, 0, '0111', '1110')\n",
    "viewer.draw(grid=True)\n",
    "\n",
    "thinkplot.subplot(2)\n",
    "viewer.step()\n",
    "viewer.draw(grid=True)\n",
    "\n",
    "plt.savefig('chap06-2.pdf')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's what it looks like as an animation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "viewer.step()\n",
    "anim = viewer.animate(frames=4, interval=500, grid=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the following cell yields a RuntimeError with a message like \"No MovieWriters available\", you probably need to install ffmpeg.  See instructions at the top of this notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "anim"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A glider is a spaceship that translates one unit down and to the right with period 4. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# glider\n",
    "glider = ['010', '001', '111']\n",
    "\n",
    "thinkplot.preplot(cols=5)\n",
    "viewer = make_viewer(4, 4, 0, 0, *glider)\n",
    "viewer.draw(grid=True)\n",
    "\n",
    "for i in range(2, 6):\n",
    "    viewer.step()\n",
    "    thinkplot.subplot(i)\n",
    "    viewer.draw(grid=True)\n",
    "    \n",
    "plt.savefig('chap06-3.pdf')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's an animation showing glider movement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "viewer = make_viewer(10, 10, 0, 0, '010', '001', '111')\n",
    "anim = viewer.animate(frames=32, interval=200, grid=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "anim"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The r-pentomino starts with only five live cells, but it runs for 1103 steps before stabilizing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# r pentomino\n",
    "rpent = ['011', '110', '010']\n",
    "\n",
    "viewer = make_viewer(3, 3, 0, 0, *rpent)\n",
    "viewer.draw(grid=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here are the start and finish configurations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# r pentomino\n",
    "rpent = ['011', '110', '010']\n",
    "\n",
    "thinkplot.preplot(cols=2)\n",
    "viewer = make_viewer(120, 120, 50, 45, *rpent)\n",
    "viewer.draw()\n",
    "\n",
    "for i in range(1103):\n",
    "    viewer.step()\n",
    "\n",
    "thinkplot.subplot(2)\n",
    "viewer.draw()\n",
    "plt.savefig('chap06-4.pdf')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And here's the animation that shows the steps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "viewer = make_viewer(120, 120, 50, 45, *rpent)\n",
    "anim = viewer.animate(frames=1200, interval=10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "anim"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Conway's conjecture"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Gosper's glider gun was the first entity to be discovered that produces an unbounded number of live cells, which refutes Conway's conjecture."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "glider_gun = [\n",
    "    '000000000000000000000000100000000000',\n",
    "    '000000000000000000000010100000000000',\n",
    "    '000000000000110000001100000000000011',\n",
    "    '000000000001000100001100000000000011',\n",
    "    '110000000010000010001100000000000000',\n",
    "    '110000000010001011000010100000000000',\n",
    "    '000000000010000010000000100000000000',\n",
    "    '000000000001000100000000000000000000',\n",
    "    '000000000000110000000000000000000000'\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's the initial configuration:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "viewer = make_viewer(11, 38, 1, 1, *glider_gun)\n",
    "viewer.draw(grid=True)\n",
    "plt.savefig('chap06-5.pdf')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And here's what it looks like running:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "viewer = make_viewer(50, 50, 2, 2, *glider_gun)\n",
    "anim = viewer.animate(frames=500, interval=20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "anim"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Implementing Game of Life\n",
    "\n",
    "As an example, I'll start with an array of random cells:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.random.randint(2, size=(10, 10)).astype(np.uint8)\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following is a straightforward translation of the GoL rules using `for` loops and array slicing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = np.zeros_like(a)\n",
    "rows, cols = a.shape\n",
    "for i in range(1, rows-1):\n",
    "    for j in range(1, cols-1):\n",
    "        state = a[i, j]\n",
    "        neighbors = a[i-1:i+2, j-1:j+2]\n",
    "        k = np.sum(neighbors) - state\n",
    "        if state:\n",
    "            if k==2 or k==3:\n",
    "                b[i, j] = 1\n",
    "        else:\n",
    "            if k == 3:\n",
    "                b[i, j] = 1\n",
    "\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's a smaller, faster version using cross correlation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.signal import correlate2d\n",
    "\n",
    "kernel = np.array([[1, 1, 1],\n",
    "                   [1, 0, 1],\n",
    "                   [1, 1, 1]])\n",
    "\n",
    "c = correlate2d(a, kernel, mode='same')\n",
    "b = (c==3) | (c==2) & a\n",
    "b = b.astype(np.uint8)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using a kernel that gives a weight of 10 to the center cell, we can simplify the logic a little."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "kernel = np.array([[1, 1, 1],\n",
    "                   [1,10, 1],\n",
    "                   [1, 1, 1]])\n",
    "\n",
    "c = correlate2d(a, kernel, mode='same')\n",
    "b = (c==3) | (c==12) | (c==13)\n",
    "b = b.astype(np.uint8)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "More importantly, the second version of the kernel makes it possible to use a look up table to get the next state, which is faster and even more concise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "table = np.zeros(20, dtype=np.uint8)\n",
    "table[[3, 12, 13]] = 1\n",
    "c = correlate2d(a, kernel, mode='same')\n",
    "b = table[c]\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:**  Start GoL in a random state and run it until it stabilizes.\n",
    "What stable patterns can you identify?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Many Game of Life patterns are available in portable file formats.  For one source, see http://www.conwaylife.com/wiki/Main_Page.\n",
    "\n",
    "Write a function to parse one of these formats and initialize the array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** One of the longest-lived small patterns is ``rabbits'', which starts with\n",
    "9 live cells and takes 17 331 steps to stabilize.  You can get the initial configuration in various formats from http://www.conwaylife.com/wiki/Rabbits.  Load this configuration\n",
    "and run it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** In my implementation, the `Life` class is based on a parent class\n",
    "called `Cell2D`, and `LifeViewer` is based on `Cell2DViewer`.  You can\n",
    "use these base classes to implement other 2-D cellular automatons.\n",
    "\n",
    "For example, one variation of GoL, called ``Highlife'', has the\n",
    "same rules as GoL, plus one additional rule: a dead cell with 6\n",
    "neighbors comes to life.\n",
    "\n",
    "Write a class named `Highlife` that inherits from `Cell2D` and implements\n",
    "this version of the rules.  Also write a class named `HighlifeViewer`\n",
    "that inherits from `Cell2DViewer` and try different ways\n",
    "to visualize the results.  As a simple example, use a different\n",
    "color map.\n",
    "\n",
    "One of the more interesting patterns in Highlife is the replicator.\n",
    "Use `add_cells` to initialize Highlife with a replicator and see what it\n",
    "does."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** \n",
    "\n",
    "If you generalize the Turing machine to two dimensions, or\n",
    "add a read-write head to a 2-D CA, the result is a\n",
    "cellular automaton called a Turmite.  It is named after a\n",
    "termite because of the way the read-write head moves, but\n",
    "spelled wrong as an homage to Alan Turing.\n",
    "\n",
    "The most famous Turmite is Langton's Ant, discovered by Chris Langton\n",
    "in 1986.  See http://en.wikipedia.org/wiki/Langton_ant.\n",
    "\n",
    "The ant is a read-write head with\n",
    "four states, which you can think of as facing north, south,\n",
    "east or west.  The cells have two states, black and white.\n",
    "\n",
    "The rules are simple.  During each time step, the ant checks the color\n",
    "of the cell it is on.  If black, the ant turns to the right,\n",
    "changes the cell to white, and moves forward one space.  If the cell\n",
    "is white, the ant turns left, changes the cell to black, and moves\n",
    "forward.\n",
    "\n",
    "Given a simple world, a simple set of rules, and only one moving part,\n",
    "you might expect to see simple behavior---but you should know\n",
    "better by now.  Starting with all white cells, Langton's ant\n",
    "moves in a seemingly random pattern for more than 10 000 steps\n",
    "before it enters a cycle with a period of 104 steps.  After\n",
    "each cycle, the ant is translated diagonally, so it leaves\n",
    "a trail called the \"highway\".\n",
    "\n",
    "Write an implementation of Langton's Ant."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
